package com.whmall.service.crm.module.companyuser.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.whmall.common.enumeration.VerifyEnum;
import com.whmall.common.util.BitMapUtils;
import com.whmall.common.util.Wh;
import com.whmall.component.common.ObjectConverter;
import com.whmall.component.entity.dto.*;
import com.whmall.component.enumeration.*;
import com.whmall.component.service.AbstractDbService;
import com.whmall.component.util.DatabaseDefaultValueUtils;
import com.whmall.component.util.DateUtils;
import com.whmall.component.util.FieldUtils;
import com.whmall.service.crm.common.PasswordEncoder;
import com.whmall.service.crm.entity.dto.company.CompanyIndustryTypeCreateOrUpdateDTO;
import com.whmall.service.crm.entity.dto.company.CompanySyncAddReqDTO;
import com.whmall.service.crm.entity.dto.companyuser.*;
import com.whmall.service.crm.entity.dto.supplierdevelop.AddControlDirectoryReqDTO;
import com.whmall.service.crm.enumeration.CompanyAndUserApplicationTypeEnum;
import com.whmall.service.crm.enumeration.CompanySourceEnum;
import com.whmall.service.crm.enumeration.CompanyUserPlatformIsBindEnum;
import com.whmall.service.crm.enumeration.SupplierControlDirectoryEnum;
import com.whmall.service.crm.exception.UserLoginFailedException;
import com.whmall.service.crm.module.company.convert.CompanyLogOperationRspDTO;
import com.whmall.service.crm.module.company.dao.*;
import com.whmall.service.crm.module.company.entity.*;
import com.whmall.service.crm.module.company.entity.qo.CompanyAndUserApplicationQO;
import com.whmall.service.crm.module.company.entity.qo.CompanyUserAddressQO;
import com.whmall.service.crm.module.company.service.CompanyAndUserApplicationService;
import com.whmall.service.crm.module.company.service.CompanyIndustryTypeService;
import com.whmall.service.crm.module.company.service.CompanyLogService;
import com.whmall.service.crm.module.company.service.CompanyService;
import com.whmall.service.crm.module.companybusinesslicense.dao.CompanyBusinessLicenseMapper;
import com.whmall.service.crm.module.companybusinesslicense.entity.CompanyBusinessLicenseDO;
import com.whmall.service.crm.module.companybusinesslicense.entity.qo.CompanyBusinessLicenseQO;
import com.whmall.service.crm.module.companyuser.CompanyUserInformationService;
import com.whmall.service.crm.module.companyuser.CompanyUserQuotationInvervalService;
import com.whmall.service.crm.module.companyuser.CompanyUserService;
import com.whmall.service.crm.module.companyuser.dao.CompanyUserInformationMapper;
import com.whmall.service.crm.module.companyuser.dao.CompanyUserMapper;
import com.whmall.service.crm.module.companyuser.dao.CompanyUserPlatformMapper;
import com.whmall.service.crm.module.companyuser.dao.CompanyUserQuotationInvervalMapper;
import com.whmall.service.crm.module.companyuser.entity.CompanyUserDO;
import com.whmall.service.crm.module.companyuser.entity.CompanyUserInformationDO;
import com.whmall.service.crm.module.companyuser.entity.CompanyUserPlatformDO;
import com.whmall.service.crm.module.companyuser.entity.qo.CompanyUserPlatformQO;
import com.whmall.service.crm.module.companyuser.entity.qo.CompanyUserQO;
import com.whmall.service.crm.module.companyuser.enumeration.EmailNotifyBitmapEnum;
import com.whmall.service.crm.module.companyusererrorcorrection.dao.CompanyUserErrorCorrectionMapper;
import com.whmall.service.crm.module.companyusererrorcorrection.entry.qo.CorrectionQO;
import com.whmall.service.crm.module.supplierdeveloppool.service.SupplierDevelopPoolService;
import com.whmall.service.crm.util.ObjectValueContrastUtil;
import com.whmall.service.crm.util.PageDTOHelper;
import com.whmall.service.crm.util.PinyinUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * CompanyUserServiceImpl
 *
 * @author alex
 * @since 2020/7/31
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CompanyUserServiceImpl extends AbstractDbService<CompanyUserMapper, CompanyUserDO> implements CompanyUserService {

    private final CompanyInformationMapper companyInformationMapper;
    private final CompanyUserMapper companyUserMapper;
    private final CompanyMapper companyMapper;
    private final CompanyService companyService;
    private final CompanyUserAddressMapper companyUserAddressMapper;
    private final CompanyUserErrorCorrectionMapper companyUserErrorCorrectionMapper;
    private final CompanyUserInformationMapper companyUserInformationMapper;
    private final CompanyUserInformationService companyUserInformationService;
    private final CompanyUserPlatformMapper companyUserPlatformMapper;
    private final ObjectConverter<CreateOrUpdateCompanyUserReqDTO, CompanyUserDO> companyUserDOConverter;
    private final ObjectConverter<CreateOrUpdateCompanyUserReqDTO, CompanyUserInformationDO> companyUserInformationDOConverter;
    private final CreateOrUpdateCompanyUserReqDTOValidator requestValidator;
    private final PasswordEncoder passwordEncoder;
    private final CompanyUserValidator companyUserValidator;

    private final SupplierDevelopPoolService supplierDevelopPoolService;
    private final CompanyAndUserApplicationService companyAndUserApplicationService;
    private final CompanyAndUserApplicationMapper companyAndUserApplicationMapper;
    private final CompanyAndUserApplicationInformationMapper companyAndUserApplicationInfoMapper;
    private final CompanyBusinessLicenseMapper companyBusinessLicenseMapper;
    private final CompanyLogMapper companyLogMapper;
    private final CompanyLogService companyLogService;
    private final CompanyUserQuotationInvervalMapper companyUserQuotationInvervalMapper;
    private final CompanyIndustryTypeMapper companyIndustryTypeMapper;
    private final CompanyIndustryTypeService companyIndustryTypeService;
    private final CompanyUserQuotationInvervalService quotationInvervalService;

    @Transactional
    @Override
    public Long createCompanyUser(Long requesterId, Long companyId, CreateOrUpdateCompanyUserReqDTO request) {
        Assert.notNull(requesterId, "创建员工ID不能为null");
        Assert.notNull(companyId, "公司ID不能为null");

        //
        // 验证
        requestValidator.validate(request);

        //
        // 创建
        CompanyUserDO companyUser = companyUserDOConverter.convert(request);
        companyUser.setBdSource(request.getBdSource());
        CompanyUserInformationDO companyUserInformation = companyUserInformationDOConverter.convert(request);

        //
        // 默认值
        companyUser.setDefaultUser((int) (System.currentTimeMillis() / 1000));
        companyUser.setVerified(VerifyEnum.YES.getValue());
        companyUser.setIsVerifiedEmail(StringUtils.hasText(request.getEmail()) ? true : false);
        // 公司ID
        companyUser.setCompanyId(companyId);

        //
        // 设置实体属性
        revalidateDatabaseDefaultValues(companyUser);
        revalidateUserRegisterTypes(companyUser);
        revalidateUserMcode(request.getName(), companyUser);

        companyUser.setPassword(passwordEncoder.encode("111111"));

        //
        // 创建员工ID、创建时间
        companyUser.setCreateId(requesterId);
        companyUser.setCreateTime(new Date());
        companyUser.setPlatformType(PlatformTypeEnum.ADMIN.getValue());

        //
        // 插入公司用户表
        try {
            companyUserMapper.insertSelective(companyUser);
        } catch (DuplicateKeyException e) {
            throw new IllegalArgumentException("邮箱或手机号已存在");
        }

        //
        // 插入公司用户信息表
        companyUserInformation.setId(companyUser.getId());
        String email = (companyUser.getEmail() == null || companyUser.getEmail().equals("") || companyUser.getEmail().startsWith("@")) ? "" : companyUser.getEmail();

//        if(StrUtil.isBlank(companyUserInformation.getInvoiceEmail())){
//            companyUserInformation.setInvoiceEmail(email);
//        }
        companyUserInformationMapper.insertSelective(companyUserInformation);


        // 新增交易报价区间
        if (CollUtil.isNotEmpty(request.getQuotationList())) {
            request.getQuotationList().forEach(e -> e.setUserId(companyUser.getId()));
            quotationInvervalService.saveOrUpdate(request.getQuotationList(), requesterId);
        }

        // 新建日志打印对比类
        String name = companyUser.getName() == null || companyUser.getName().equals("") ? "" : companyUser.getName();
        email = (companyUser.getEmail() == null || companyUser.getEmail().equals("") || companyUser.getEmail().startsWith("@")) ? "" : companyUser.getEmail();
        String mobile = (companyUser.getMobile() == null || companyUser.getMobile().equals("") || companyUser.getMobile().startsWith("@")) ? "" : companyUser.getMobile();

        CompanyLogDO logDO = CompanyLogDO.builder()
                .companyId(companyId)
                .createType(OperatorTypeEnum.EMPLOYEE.getValue())
                .createId(requesterId)
                .operationType(CompanyLogOperationTypeEnum.UPDATE_USER_INFORMATION.getValue())
                .operationDesc1("后台新增用户\"" + name
                        + email
                        + mobile + "\""
                )
                .createTime(new Date())
                .ip(request.getIp())
                .build();
        companyLogMapper.insertSelective(logDO);
        //
        // 返回新创建的ID
        return companyUser.getId();
    }

    @Override
    public CompanyUserSyncAddRspDTO syncCreateCompanyUser(CompanyUserSyncAddReqDTO reqDTO, Long companyId, OperatorReqDTO operator) {
        //
        // 创建
        CompanyUserDO companyUser = BeanUtil.copyProperties(reqDTO,CompanyUserDO.class);
        CompanyUserInformationDO companyUserInformation = BeanUtil.copyProperties(reqDTO,CompanyUserInformationDO.class);

        //
        // 默认值
        companyUser.setDefaultUser((int) (System.currentTimeMillis() / 1000));
        companyUser.setVerified(VerifyEnum.YES.getValue());
        companyUser.setIsVerifiedEmail(StringUtils.hasText(reqDTO.getEmail()) ? true : false);
        // 公司ID
        companyUser.setCompanyId(companyId);

        //
        // 设置实体属性
        if (!StringUtils.hasLength(companyUser.getEmail())) {
            companyUser.setEmail(DatabaseDefaultValueUtils.createMillisecondDefaultValue());
        }
        if (!StringUtils.hasLength(companyUser.getMobile())) {
            companyUser.setMobile(DatabaseDefaultValueUtils.createMillisecondDefaultValue());
        }
        revalidateUserRegisterTypes(companyUser);
        revalidateUserMcode(reqDTO.getName(), companyUser);

        companyUser.setPassword(passwordEncoder.encode("111111"));

        //
        // 创建员工ID、创建时间
        companyUser.setCreateId(operator.getOperatorId());
        companyUser.setCreateTime(new Date());
        companyUser.setPlatformType(PlatformTypeEnum.INTERFACE.getValue());

        //
        // 插入公司用户表
        try {
            companyUserMapper.insertSelective(companyUser);
        } catch (DuplicateKeyException e) {
            throw new IllegalArgumentException("邮箱或手机号已存在");
        }

        //
        // 插入公司用户信息表
        companyUserInformation.setId(companyUser.getId());
        companyUserInformationMapper.insertSelective(companyUserInformation);

        // 新建日志打印对比类
        String email = (StrUtil.isBlank(companyUser.getEmail()) || companyUser.getEmail().startsWith("@")) ? "" : companyUser.getEmail();
        String mobile = (StrUtil.isBlank(companyUser.getMobile()) || companyUser.getMobile().startsWith("@")) ? "" : companyUser.getMobile();
        String name = StrUtil.isBlank(companyUser.getName()) ? "" : companyUser.getName();

        CompanyLogDO logDO = CompanyLogDO.builder()
                .companyId(companyId)
                .createType(operator.getOperatorType().getValue())
                .createId(operator.getOperatorId())
                .operationType(CompanyLogOperationTypeEnum.UPDATE_USER_INFORMATION.getValue())
                .operationDesc1("后台新增用户\"" + name
                        + email
                        + mobile + "\""
                )
                .createTime(new Date())
                .ip(operator.getIp())
                .build();
        companyLogMapper.insertSelective(logDO);
        //
        // 返回新创建的ID
        return CompanyUserSyncAddRspDTO
                .builder()
                .userId(companyUser.getId())
                .companyId(companyUser.getCompanyId())
                .build();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Map<String, CompanyUserSyncAddRspDTO> batchSyncCreateUser(List<CompanyUserSyncAddReqDTO> userList,
                                                                     List<CompanySyncAddReqDTO> companyList,
                                                                     OperatorReqDTO operator) {
        if(CollUtil.isEmpty(userList)){
            return MapUtil.empty();
        }

        List<CompanyUserDO> companyUserDOList = new ArrayList<>(userList.size());
        List<CompanyUserInformationDO> companyUserInformationDOList = new ArrayList<>(userList.size());
        List<CompanyLogDO> companyLogDOList = new ArrayList<>(companyList.size());

        userList.forEach(reqDTO -> {

            CompanyUserDO companyUser = new CompanyUserDO();
            BeanUtils.copyProperties(reqDTO, companyUser);
            companyUser.setDefaultUser((int) (System.currentTimeMillis() / 1000));
            companyUser.setVerified(VerifyEnum.YES.getValue());
            companyUser.setIsVerifiedEmail(StringUtils.hasText(reqDTO.getEmail()) ? true : false);

            //
            // 设置实体属性
            if (!StringUtils.hasLength(companyUser.getEmail())) {
                companyUser.setEmail(DatabaseDefaultValueUtils.createMillisecondDefaultValue());
            }
            if (!StringUtils.hasLength(companyUser.getMobile())) {
                companyUser.setMobile(DatabaseDefaultValueUtils.createMillisecondDefaultValue());
            }
            revalidateUserRegisterTypes(companyUser);
            revalidateUserMcode(reqDTO.getName(), companyUser);

            companyUser.setPassword(passwordEncoder.encode("111111"));

            //
            // 创建员工ID、创建时间
            companyUser.setCreateId(operator.getOperatorId());
            companyUser.setCreateTime(new Date());
            companyUser.setPlatformType(PlatformTypeEnum.INTERFACE.getValue());

            companyUserDOList.add(companyUser);

            CompanyUserInformationDO companyUserInformation = BeanUtil.copyProperties(reqDTO,CompanyUserInformationDO.class);
            companyUserInformation.setPosition(StrUtil.EMPTY);
            companyUserInformation.setDepartment(StrUtil.EMPTY);
            companyUserInformation.setNotifyBitmap(StrUtil.EMPTY);
            companyUserInformation.setCustomerLockReason(StrUtil.EMPTY);
            companyUserInformation.setSupplierLockReason(StrUtil.EMPTY);
            companyUserInformation.setPurchaserComment(StrUtil.EMPTY);
            companyUserInformation.setSupplierContact(StrUtil.EMPTY);
            companyUserInformation.setAvatar(StrUtil.EMPTY);
            companyUserInformation.setPreference(StrUtil.EMPTY);
            companyUserInformation.setInvoiceEmail(StrUtil.EMPTY);

            companyUserInformationDOList.add(companyUserInformation);

            // 新建日志打印对比类
            String email = (StrUtil.isBlank(companyUser.getEmail()) || companyUser.getEmail().startsWith("@")) ? "" : companyUser.getEmail();
            String mobile = (StrUtil.isBlank(companyUser.getMobile()) || companyUser.getMobile().startsWith("@")) ? "" : companyUser.getMobile();
            String name = StrUtil.isBlank(companyUser.getName()) ? "" : companyUser.getName();

            companyLogDOList.add(CompanyLogDO.builder()
                    .companyId(reqDTO.getCompanyId())
                    .createType(operator.getOperatorType().getValue())
                    .createId(operator.getOperatorId())
                    .operationType(CompanyLogOperationTypeEnum.UPDATE_USER_INFORMATION.getValue())
                    .operationDesc1("后台新增用户\"" + name
                            + email
                            + mobile + "\""
                    )
                    .createTime(new Date())
                    .ip(operator.getIp())
                    .build());
        });

        if(CollUtil.isEmpty(companyUserDOList)){
            return MapUtil.empty();
        }

        // 存在新建公司 先创建
        Map<String,Long> companyIdMap = CollUtil.isNotEmpty(companyList)
                ? companyService.batchSyncCreateCompany(companyList,operator)
                : MapUtil.empty();

        List<CompanyUserDO> addUserList = new ArrayList<>();
        List<CompanyUserInformationDO> addInfoList = new ArrayList<>();
        List<CompanyLogDO> addLogList = new ArrayList<>();
        
        for (int i = 0; i < companyUserDOList.size(); i++) {

            // 公司已存在 无需新增
            if(Wh.Num.meaningful(companyUserDOList.get(i).getCompanyId(),0L)){
               addUserList.add(companyUserDOList.get(i));
               addInfoList.add(companyUserInformationDOList.get(i));
               addLogList.add(companyLogDOList.get(i));
               continue;
            }

            if(MapUtil.isNotEmpty(companyIdMap) && companyIdMap.containsKey(companyUserDOList.get(i).getCompanyName())){
                companyUserDOList.get(i).setCompanyId(companyIdMap.get(companyUserDOList.get(i).getCompanyName()));
                addUserList.add(companyUserDOList.get(i));
                addInfoList.add(companyUserInformationDOList.get(i));
                addLogList.add(companyLogDOList.get(i));
                continue;
            }

        }

        // 批量创建公司用户数据
        Map<String,CompanyUserSyncAddRspDTO> resultMap = new HashMap<>();
        if(CollUtil.isEmpty(addUserList)){
            return MapUtil.empty();
        }
        super.saveBatch(addUserList);
        for (int i = 0; i < addUserList.size(); i++) {
            CompanyUserDO companyUserDO = addUserList.get(i);
            addInfoList.get(i).setId(companyUserDO.getId());
            resultMap.put(companyUserDO.getMobile(),CompanyUserSyncAddRspDTO
                    .builder()
                    .userId(companyUserDO.getId())
                    .companyId(companyUserDO.getCompanyId())
                    .build());
        }

        companyUserInformationService.saveBatch(addInfoList);
        companyLogService.saveBatch(addLogList);

        return resultMap;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateCompanyUser(Long requesterId, Long companyId, Long companyUserId, CreateOrUpdateCompanyUserReqDTO request) {
        Assert.notNull(requesterId, "更新员工ID不能为null");

        //
        // 验证
        requestValidator.validate(request, true);
        CompanyUserDO exist = getCompanyUserOrThrow(companyId, companyUserId);

        //
        // 创建更新实体
        CompanyUserDO companyUser = companyUserDOConverter.convert(request);
        companyUser.setBdSource(request.getBdSource());
        CompanyUserInformationDO companyUserInformation = companyUserInformationDOConverter.convert(request);

        //
        // 公司用户ID
        companyUser.setId(companyUserId);
        companyUserInformation.setId(companyUserId);

        // 邮箱变化 更新邮箱认证状态
        String existEmail = DatabaseDefaultValueUtils.erasureMillisecondDefaultValueIfExist(exist.getEmail());
        String newEmail = StringUtils.hasText(request.getEmail()) ? request.getEmail() : "";

        // 邮箱变化
        if (!existEmail.equals(newEmail)) {
            companyUser.setIsVerifiedEmail(StringUtils.hasText(newEmail) ? true : false);
        }

        //
        // 设置实体属性
        revalidateDatabaseDefaultValues(companyUser);
        revalidateUserRegisterTypes(companyUser);
        revalidateUserMcode(request.getName(), companyUser);


        //
        // 更新员工ID、更新时间
        companyUser.setUpdateId(requesterId);
        companyUser.setUpdateTime(new Date());
        CompanyUserDO companyUserDO = companyUserMapper.getById(companyUser.getId());
        companyUserDO.setMobile(request.getOldMobile());
        CompanyUserInformationDO companyUserInformationDO = companyUserInformationMapper.getById(companyUserId);
        //
        // 更新公司用户表
        try {
            companyUserMapper.updateByIdSelective(companyUser);
        } catch (DuplicateKeyException e) {
            throw new IllegalArgumentException("邮箱或手机号已存在");
        }

        //
        // 更新公司用户信息表
        if (!CompanyUserUtils.isEmptyEntity(companyUserInformation)) {
//            String email = (companyUser.getEmail() == null || companyUser.getEmail().equals("") || companyUser.getEmail().startsWith("@")) ? "" : companyUser.getEmail();

//            if(StrUtil.isBlank(companyUserInformation.getInvoiceEmail())){
//                companyUserInformation.setInvoiceEmail(email);
//            }

            companyUserInformation.setNotifyBitmap(BitMapUtils.toBitMapString(request.getNotifyList(), BitMapUtils.EMAIL_NOTIFY_LENGTH));
            companyUserInformationMapper.updateByIdSelective(companyUserInformation);
        } else {
            companyUserInformationMapper.updateByIdSelective(CompanyUserInformationDO.builder()
                    .id(companyUserId)
                    .notifyBitmap(BitMapUtils.toBitMapString(request.getNotifyList(), BitMapUtils.EMAIL_NOTIFY_LENGTH))
                    .build());
        }
        // 新建日志打印对比类
        String email = (companyUserDO.getEmail().equals("") || companyUserDO.getEmail().startsWith("@")) ? "" : companyUserDO.getEmail();
        String mobile = (companyUserDO.getMobile().equals("") || companyUserDO.getMobile().startsWith("@")) ? "" : companyUserDO.getMobile();

        String remark = "将用户\"" + companyUserDO.getName()
                + email
                + mobile + "\"";

        CompanyLogOperationRspDTO oldLog = CompanyLogOperationRspDTO.builder()
                .userName(companyUserDO.getName())
                .mobile((companyUserDO.getMobile().equals("") || companyUserDO.getMobile().startsWith("@")) ? "" : companyUserDO.getMobile())
                .email((companyUserDO.getEmail().equals("") || companyUserDO.getEmail().startsWith("@")) ? "" : companyUserDO.getEmail())
                .isAutoQuotation(companyUserInformationDO.getIsAutoQuotation() == 0 ? "取消自动交易" : "设置为自动交易")
                .qq(companyUserDO.getQq())
                .tel(companyUserDO.getTel())
                .expressCompany(Objects.nonNull(companyUserDO.getExpressCompany()) && companyUserDO.getExpressCompany().equals(6) ? "顺丰" :
                        Objects.nonNull(companyUserDO.getExpressCompany()) && companyUserDO.getExpressCompany().equals(8) ? "申通" : "")
                .preference(companyUserInformationDO.getPreference())
                .build();
        CompanyLogOperationRspDTO newLog = CompanyLogOperationRspDTO.builder()
                .userName(request.getName())
                .mobile((request.getMobile() == null || request.getMobile().equals("") || request.getMobile().startsWith("@")) ? null : request.getMobile())
                .email((request.getEmail() == null || request.getEmail().equals("") || request.getEmail().startsWith("@")) ? null : request.getEmail())
                .isAutoQuotation(request.getIsAutoQuotation() == 0 ? "取消自动交易" : "设置为自动交易用户")
                .expressCompany(Objects.nonNull(request.getExpressCompany()) && request.getExpressCompany().equals(6) ? "顺丰" :
                        Objects.nonNull(request.getExpressCompany()) && request.getExpressCompany().equals(8) ? "申通" : "")
                .qq(request.getQq())
                .tel(request.getTel())
                .preference(request.getPreference())
                .build();
        String operation = getRemark(ObjectValueContrastUtil.compareTwoClass(oldLog, newLog));
        CompanyLogDO logDO = CompanyLogDO.builder()
                .companyId(companyId)
                .createType(OperatorTypeEnum.EMPLOYEE.getValue())
                .createId(requesterId)
                .operationType(CompanyLogOperationTypeEnum.UPDATE_USER_INFORMATION.getValue())
                .operationDesc1(remark + operation)
                .createTime(new Date())
                .ip(request.getIp())
                .build();
        if (operation != null && !operation.equals("")) {
            companyLogMapper.insertSelective(logDO);
        }
    }

    public String getRemark(Map<String, List<Object>> map) {
        String remark = "";
        remark = map.entrySet().stream().map(e -> {
            String mssage = "";
            if (e.getKey().equals("交易")) {
                mssage = e.getValue().get(1) + "";
            } else {
                mssage = e.getKey() + " 更新为 " + "\"" + e.getValue().get(1) + "\"";

            }


            return mssage;
        }).collect(Collectors.joining(","));
        return remark;

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateEmailNotify(Long userId, List<Integer> notifyList, OperatorReqDTO operatorReqDTO) {
        CompanyUserDO userOld = companyUserMapper.getById(userId);
        CompanyUserInformationDO userInfoOld = companyUserInformationMapper.getById(userId);
        companyUserMapper.updateByIdSelective(CompanyUserDO.builder()
                .id(userId)
                .updateId(operatorReqDTO.getOperatorId())
                .updateType(operatorReqDTO.getOperatorType().getValue())
                .updateTime(new Date())
                .build());
        companyUserInformationMapper.updateByIdSelective(CompanyUserInformationDO.builder()
                .id(userId)
                .notifyBitmap(BitMapUtils.toBitMapString(notifyList, BitMapUtils.EMAIL_NOTIFY_LENGTH))
                .build());
        // 公司日志
        List<Integer> onIndexs = new ArrayList<>(), offIndexs = new ArrayList<>();
        Arrays.stream(EmailNotifyBitmapEnum.values()).forEach(e -> {
            if (userInfoOld.getNotifyBitmap().length() > e.getIndex()
                    && userInfoOld.getNotifyBitmap().charAt(e.getIndex()) == '1'
                    && notifyList.contains(e.getIndex())) {
                onIndexs.add(e.getIndex());
            } else if ((userInfoOld.getNotifyBitmap().length() <= e.getIndex()
                    || userInfoOld.getNotifyBitmap().charAt(e.getIndex()) == '0')
                    && !notifyList.contains(e.getIndex())) {
                offIndexs.add(e.getIndex());
            }
        });
        if (!onIndexs.isEmpty() || !offIndexs.isEmpty()) {
            CompanyLogDO logDO = CompanyLogDO.builder()
                    .companyId(userOld.getCompanyId())
                    .createType(operatorReqDTO.getOperatorType().getValue())
                    .createId(operatorReqDTO.getOperatorId())
                    .operationType(CompanyLogOperationTypeEnum.UPDATE_USER_INFORMATION.getValue())
                    .operationDesc1("将用户“" +
                            Stream.of(userOld.getName(), userOld.getEmail(), userOld.getMobile())
                                    .filter(e -> StringUtils.hasText(FieldUtils.unwrapString(e)))
                                    .collect(Collectors.joining(" ")) + "”"
                            + (!onIndexs.isEmpty() ? " 打开邮件推送开关：" + onIndexs.stream()
                            .map(e -> EmailNotifyBitmapEnum.fromIndex(e).getName()).collect(Collectors.joining("、"))
                            : "")
                            + (!offIndexs.isEmpty() ? " 关闭邮件推送开关：" + offIndexs.stream()
                            .map(e -> EmailNotifyBitmapEnum.fromIndex(e).getName()).collect(Collectors.joining("、"))
                            : ""))
                    .ip(null).createTime(new Date()).build();
            companyLogMapper.insertSelective(logDO);
        }
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void lockBuy(Long requesterId, Long companyId, Long companyUserId, String lockReason) {
        Assert.notNull(requesterId, "更新员工ID不能为null");
        Assert.notNull(lockReason, "锁定原因不能为null");
        CompanyUserDO companyUser = getCompanyUserOrThrow(companyId, companyUserId);
        if (companyUser.getIsLockedBuy()) {
            throw new IllegalArgumentException("该用户已经锁定了采购");
        }

        companyUser = new CompanyUserDO();
        companyUser.setId(companyUserId);
        companyUser.setIsLockedBuy(true);
        companyUser.setUpdateId(requesterId);
        companyUser.setUpdateTime(new Date());

        CompanyUserInformationDO companyUserInformation = new CompanyUserInformationDO();
        companyUserInformation.setId(companyUserId);
        companyUserInformation.setCustomerLockReason(lockReason);
        // 添加操作日志
        CompanyUserDO companyUserDO = companyUserMapper.getById(companyUser.getId());
        String email = (companyUserDO.getEmail().equals("") || companyUserDO.getEmail().startsWith("@")) ? "" : companyUserDO.getEmail();
        String mobile = (companyUserDO.getMobile().equals("") || companyUserDO.getMobile().startsWith("@")) ? "" : companyUserDO.getMobile();

        String remark = "采购冻结账号\"" + companyUserDO.getName()
                + email
                + mobile + "\""
                + "原因" + "\"" + lockReason + "\"";

        companyUserMapper.updateByIdSelective(companyUser);
        companyUserInformationMapper.updateByIdSelective(companyUserInformation);
        CompanyLogDO logDO = CompanyLogDO.builder()
                .companyId(companyId)
                .createType(OperatorTypeEnum.EMPLOYEE.getValue())
                .createId(requesterId)
                .operationType(CompanyLogOperationTypeEnum.UPDATE_USER_INFORMATION.getValue())
                .operationDesc1(remark)
                .createTime(new Date())
                .ip("")
                .build();
        companyLogMapper.insertSelective(logDO);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void unlockBuy(Long requesterId, Long companyId, Long companyUserId) {
        Assert.notNull(requesterId, "更新员工ID不能为null");

        CompanyUserDO companyUser = getCompanyUserOrThrow(companyId, companyUserId);
        if (!companyUser.getIsLockedBuy()) {
            throw new IllegalArgumentException("该用户并未被锁定采购");
        }

        companyUser = new CompanyUserDO();
        companyUser.setId(companyUserId);
        companyUser.setIsLockedBuy(false);
        companyUser.setUpdateId(requesterId);
        companyUser.setUpdateTime(new Date());

        CompanyUserInformationDO companyUserInformation = new CompanyUserInformationDO();
        companyUserInformation.setId(companyUserId);
        companyUserInformation.setCustomerLockReason("");
        // 新建日志打印对比类
        CompanyUserDO companyUserDO = companyUserMapper.getById(companyUser.getId());

        String email = (companyUserDO.getEmail().equals("") || companyUserDO.getEmail().startsWith("@")) ? "" : companyUserDO.getEmail();
        String mobile = (companyUserDO.getMobile().equals("") || companyUserDO.getMobile().startsWith("@")) ? "" : companyUserDO.getMobile();

        String remark = "解除采购冻结账号\"" + companyUserDO.getName()
                + email
                + mobile + "\"";
        companyUserMapper.updateByIdSelective(companyUser);
        companyUserInformationMapper.updateByIdSelective(companyUserInformation);
        CompanyLogDO logDO = CompanyLogDO.builder()
                .companyId(companyId)
                .createType(OperatorTypeEnum.EMPLOYEE.getValue())
                .createId(requesterId)
                .operationType(CompanyLogOperationTypeEnum.UPDATE_USER_INFORMATION.getValue())
                .operationDesc1(remark)
                .createTime(new Date())
                .ip("")
                .build();
        companyLogMapper.insertSelective(logDO);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void lockSale(Long requesterId, Long companyId, Long companyUserId, String lockReason) {
        Assert.notNull(requesterId, "更新员工ID不能为null");
        Assert.notNull(lockReason, "锁定原因不能为null");
        CompanyUserDO companyUser = getCompanyUserOrThrow(companyId, companyUserId);
        if (companyUser.getIsLockedSale()) {
            throw new IllegalArgumentException("该用户已经锁定了销售");
        }

        companyUser = new CompanyUserDO();
        companyUser.setId(companyUserId);
        companyUser.setIsLockedSale(true);
        companyUser.setUpdateId(requesterId);
        companyUser.setUpdateTime(new Date());

        CompanyUserInformationDO companyUserInformation = new CompanyUserInformationDO();
        companyUserInformation.setId(companyUserId);
        companyUserInformation.setSupplierLockReason(lockReason);
        // 添加操作日志
        CompanyUserDO companyUserDO = companyUserMapper.getById(companyUser.getId());
        String email = (companyUserDO.getEmail().equals("") || companyUserDO.getEmail().startsWith("@")) ? "" : companyUserDO.getEmail();
        String mobile = (companyUserDO.getMobile().equals("") || companyUserDO.getMobile().startsWith("@")) ? "" : companyUserDO.getMobile();

        String remark = "销售冻结账号\"" + companyUserDO.getName()
                + email
                + mobile + "\""
                + "原因" + "\"" + lockReason + "\"";

        companyUserMapper.updateByIdSelective(companyUser);
        companyUserInformationMapper.updateByIdSelective(companyUserInformation);
        // 修改控制目录
        supplierDevelopPoolService.addControlDirectory(AddControlDirectoryReqDTO
                .builder().companyId(companyId)
                .employeeId(requesterId)
                .supplierControlDirectory(SupplierControlDirectoryEnum.SALES_LOCK_ACCOUNT_COMPANY.getValue())
                .build());
        CompanyLogDO logDO = CompanyLogDO.builder()
                .companyId(companyId)
                .createType(OperatorTypeEnum.EMPLOYEE.getValue())
                .createId(requesterId)
                .operationType(CompanyLogOperationTypeEnum.UPDATE_USER_INFORMATION.getValue())
                .operationDesc1(remark)
                .createTime(new Date())
                .ip("")
                .build();
        companyLogMapper.insertSelective(logDO);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void unlockSale(Long requesterId, Long companyId, Long companyUserId) {
        Assert.notNull(requesterId, "更新员工ID不能为null");
        CompanyUserDO companyUser = getCompanyUserOrThrow(companyId, companyUserId);
        if (!companyUser.getIsLockedSale()) {
            throw new IllegalArgumentException("该用户并未被锁定销售");
        }

        companyUser = new CompanyUserDO();
        companyUser.setId(companyUserId);
        companyUser.setIsLockedSale(false);
        companyUser.setUpdateId(requesterId);
        companyUser.setUpdateTime(new Date());

        CompanyUserInformationDO companyUserInformation = new CompanyUserInformationDO();
        companyUserInformation.setId(companyUserId);
        companyUserInformation.setSupplierLockReason("");
        // 添加操作日志
        CompanyUserDO companyUserDO = companyUserMapper.getById(companyUser.getId());
        String email = (companyUserDO.getEmail().equals("") || companyUserDO.getEmail().startsWith("@")) ? "" : companyUserDO.getEmail();
        String mobile = (companyUserDO.getMobile().equals("") || companyUserDO.getMobile().startsWith("@")) ? "" : companyUserDO.getMobile();

        String remark = "解除销售冻结账号\"" + companyUserDO.getName()
                + email
                + mobile + "\"";
        companyUserMapper.updateByIdSelective(companyUser);
        companyUserInformationMapper.updateByIdSelective(companyUserInformation);
        CompanyDO companyDO = companyMapper.selectById(companyId);
        // 修改 供应商试剂目录
        Integer directory = companyDO.getSupplierControlDirectory();
        if (!directory.equals(SupplierControlDirectoryEnum.SIGNED_COOPERATION_SUPPLIER.getValue())
                && !directory.equals(SupplierControlDirectoryEnum.OTHER_SITUATION.getValue())) {
            supplierDevelopPoolService.removeControlDirectory(requesterId, companyId);
        }
        CompanyLogDO logDO = CompanyLogDO.builder()
                .companyId(companyId)
                .createType(OperatorTypeEnum.EMPLOYEE.getValue())
                .createId(requesterId)
                .operationType(CompanyLogOperationTypeEnum.UPDATE_USER_INFORMATION.getValue())
                .operationDesc1(remark)
                .createTime(new Date())
                .ip("")
                .build();
        companyLogMapper.insertSelective(logDO);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void setDefaultUser(Long requesterId, Long companyId, Long companyUserId) {
        Assert.notNull(requesterId, "更新员工ID不能为null");
        Assert.notNull(companyId, "公司ID不能为null");
        Assert.notNull(companyUserId, "公司用户ID不能为null");

        CompanyUserDO defaultUser = companyUserMapper.getDefaultByCompanyId(companyId);

        //
        // 取消之前的默认用户
        if (null != defaultUser) {
            CompanyUserDO updayeDefaultUser = new CompanyUserDO();
            updayeDefaultUser.setId(defaultUser.getId());
            updayeDefaultUser.setDefaultUser((int) (System.currentTimeMillis() / 1000));
            updayeDefaultUser.setUpdateId(requesterId);
            updayeDefaultUser.setUpdateTime(new Date());
            companyUserMapper.updateByIdSelective(updayeDefaultUser);
        }
        if (null == defaultUser || defaultUser.getId() != companyUserId.longValue()) {
            CompanyUserDO newDefaultUser = getCompanyUserOrThrow(companyId, companyUserId);
            newDefaultUser.setId(companyUserId);
            newDefaultUser.setDefaultUser(1);
            newDefaultUser.setUpdateId(requesterId);
            newDefaultUser.setUpdateTime(new Date());
            companyUserMapper.updateByIdSelective(newDefaultUser);
        }
    }

    @Override
    public List<CompanyUserListByUsernameRspDTO> listByUsername(String username, Integer rule, Integer limitNum) {
        if (!StringUtils.hasText(username)) {
            return null;
        }
        CompanyUserQO qo = CompanyUserQO.builder()
                .usernameLike(username)
                .rule(rule)
                .orderBy("id desc")
                .build();
        if (limitNum != null) {
            PageDTOHelper.startPage(PageReqDTO.builder().pageNum(1).pageSize(limitNum).build());
        }
        List<CompanyUserDO> users = companyUserMapper.listBy(qo);
        Map<Long, CompanyDO> companys = users.size() > 0 ?
                companyMapper.getByIds(
                                users.stream().map(CompanyUserDO::getCompanyId).collect(Collectors.toList()))
                        .stream().collect(Collectors.toMap(CompanyDO::getId, e -> e)) : new HashMap<>(1);
        return users.stream().map(e ->
                CompanyUserListByUsernameRspDTO.builder()
                        .id(e.getId())
                        .name(e.getName())
                        .mobile(FieldUtils.unwrapString(e.getMobile()))
                        .email(FieldUtils.unwrapString(e.getEmail()))
                        .companyName(companys.get(e.getCompanyId()).getName())
                        .build()
        ).collect(Collectors.toList());
    }

    @Override
    public CompanyUserKeyFieldRspDTO findById(Long id) {
        CompanyUserDO user = companyUserMapper.getById(id);
        if (user == null) {
            return null;
        }
        CompanyUserInformationDO userInfo = companyUserInformationMapper.getById(id);
        CompanyUserKeyFieldRspDTO rspDTO = new CompanyUserKeyFieldRspDTO();
        BeanUtils.copyProperties(user, rspDTO);
        BeanUtils.copyProperties(userInfo, rspDTO);
        rspDTO.setMobile(FieldUtils.unwrapString(rspDTO.getMobile()));
        rspDTO.setEmail(FieldUtils.unwrapString(rspDTO.getEmail()));
        return rspDTO;
    }

    @Override
    public Map<Long, CompanyUserKeyFieldRspDTO> listByIds(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.emptyMap();
        }
        ids = ids.stream().distinct().collect(Collectors.toList());
        List<CompanyUserDO> users = companyUserMapper.listBy(CompanyUserQO.builder().ids(ids).build());
        Map<Long, CompanyUserInformationDO> userInfos = companyUserInformationMapper.listByIds(ids)
                .stream().collect(Collectors.toMap(CompanyUserInformationDO::getId, e -> e));
        Map<Long, String> companys = users.size() > 0 ?
                companyMapper.getByIds(
                                users.stream().map(CompanyUserDO::getCompanyId).collect(Collectors.toList()))
                        .stream().collect(Collectors.toMap(CompanyDO::getId, CompanyDO::getName))
                : null;
        // 判断
        ids = userInfos.values().stream().filter(e -> e.getIsAutoQuotation() == 1).map(e -> e.getId()).collect(Collectors.toList());
        Map<Long, List<QuotationInvervalDTO>> quotationInverval = new HashMap<Long, List<QuotationInvervalDTO>>();
        if (ids != null && !ids.isEmpty()) {
            quotationInverval = companyUserQuotationInvervalMapper.selectByUserIds(ids).stream().map(
                    e -> {
                        QuotationInvervalDTO dto = new QuotationInvervalDTO();
                        BeanUtils.copyProperties(e, dto);
                        return dto;
                    }
            ).collect(Collectors.groupingBy(QuotationInvervalDTO::getUserId));
        }
        Map<Long, List<QuotationInvervalDTO>> finalQuotationInverval = quotationInverval;
        return users.stream().collect(Collectors.toMap(CompanyUserDO::getId, e -> {
            CompanyUserKeyFieldRspDTO rspDTO = new CompanyUserKeyFieldRspDTO();
            BeanUtils.copyProperties(e, rspDTO);
            BeanUtils.copyProperties(userInfos.get(e.getId()), rspDTO);
            rspDTO.setMobile(FieldUtils.unwrapString(e.getMobile()));
            rspDTO.setEmail(FieldUtils.unwrapString(e.getEmail()));
            rspDTO.setDefaultUser(FieldUtils.unwrapDefault(e.getDefaultUser()));
            rspDTO.setCompanyName(companys.get(e.getCompanyId()));
            rspDTO.setQuotationIntervalList(finalQuotationInverval.get(e.getId()));
            return rspDTO;
        }));
    }

    @Override
    public Map<Long, CompanyUserKeyFieldRspDTO> listByIds(CompanyUserQueryReqDTO reqDTO) {
        if (CollectionUtils.isEmpty(reqDTO.getIds())) {
            return Collections.emptyMap();
        }
        CompanyUserQO qo = CompanyUserQO.builder()
                .ids(reqDTO.getIds())
                .build();
        List<CompanyUserDO> users = companyUserMapper.listBy(qo);
        if (users.isEmpty()) {
            return Collections.emptyMap();
        }
        List<Long> userIds = users.stream().map(CompanyUserDO::getId).collect(Collectors.toList());
        Map<Long, CompanyUserInformationDO> informationMap = companyUserInformationMapper.listByIds(userIds).stream()
                .collect(Collectors.toMap(CompanyUserInformationDO::getId, e -> e));
        return users.stream()
                .collect(Collectors.toMap(CompanyUserDO::getId, e -> {
                    CompanyUserKeyFieldRspDTO rspDTO = new CompanyUserKeyFieldRspDTO();
                    BeanUtils.copyProperties(e, rspDTO);
                    BeanUtils.copyProperties(informationMap.get(e.getId()), rspDTO);
                    rspDTO.setMobile(FieldUtils.unwrapString(e.getMobile()));
                    rspDTO.setEmail(FieldUtils.unwrapString(e.getEmail()));
                    rspDTO.setDefaultUser(FieldUtils.unwrapDefault(e.getDefaultUser()));
                    return rspDTO;
                }));
    }

    @Override
    public Map<String, CompanyUserKeyFieldRspDTO> queryByOneField(CompanyUserQueryByOneFieldReqDTO reqDTO) {
        if (CollectionUtils.isEmpty(reqDTO.getItems())) {
            return Collections.emptyMap();
        }
        String field = null;
        CompanyUserQO qo = CompanyUserQO.builder().isLockedBuy(reqDTO.getIsLockedBuy()).build();
        if (StringUtils.hasText(reqDTO.getItems().get(0).getMobile())) {
            field = "mobile";
            qo.setMobiles(new ArrayList<>(reqDTO.getItems().stream().map(CompanyUserQueryByOneFieldItemReqDTO::getMobile).collect(Collectors.toSet())));
        } else if (StringUtils.hasText(reqDTO.getItems().get(0).getEmail())) {
            field = "email";
            qo.setEmails(new ArrayList<>(reqDTO.getItems().stream().map(CompanyUserQueryByOneFieldItemReqDTO::getEmail).collect(Collectors.toSet())));
        }
        List<CompanyUserDO> users = companyUserMapper.listBy(qo);
        Map<Long, CompanyUserInformationDO> userInfos = users.size() > 0 ?
                companyUserInformationMapper.listByIds(
                                users.stream().map(e -> e.getId()).collect(Collectors.toList()))
                        .stream().collect(Collectors.toMap(CompanyUserInformationDO::getId, e -> e)) : null;
        return users.stream().collect(Collectors.toMap(
                "mobile".equals(field) ? CompanyUserDO::getMobile : CompanyUserDO::getEmail, e ->
                        CompanyUserKeyFieldRspDTO.builder()
                                .id(e.getId())
                                .name(e.getName())
                                .mobile(FieldUtils.unwrapString(e.getMobile()))
                                .email(FieldUtils.unwrapString(e.getEmail()))
                                .companyId(e.getCompanyId())
                                .purchaserComment(userInfos.get(e.getId()).getPurchaserComment())
                                .isAutoQuotation(userInfos.get(e.getId()).getIsAutoQuotation())
                                .build(),
                (v1, v2) -> v1
        ));
    }

    private CompanyUserDO getCompanyUserOrThrow(Long companyId, Long companyUserId) {
        Assert.notNull(companyId, "公司ID不能为null");
        Assert.notNull(companyUserId, "公司用户ID不能为null");

        CompanyUserDO exist = companyUserMapper.getById(companyUserId);
        if (null == exist || !exist.getCompanyId().equals(companyId)) {
            throw new IllegalArgumentException("公司用户不存在");
        }

        return exist;
    }

    private void revalidateDatabaseDefaultValues(CompanyUserDO companyUser) {
        requestValidator.afterPropertySetValidate(companyUser);
        if (!StringUtils.hasLength(companyUser.getEmail())) {
            companyUser.setEmail(DatabaseDefaultValueUtils.createMillisecondDefaultValue());
        }
        if (!StringUtils.hasLength(companyUser.getMobile())) {
            companyUser.setMobile(DatabaseDefaultValueUtils.createMillisecondDefaultValue());
        }
    }

    //
    // 助记码
    private void revalidateUserMcode(String name, CompanyUserDO companyUser) {
        if (StringUtils.hasText(name)) {
            companyUser.setMcode(PinyinUtils.toPinyinFirstLetters(name));
        }
    }

    //
    // 用户注册行为
    private void revalidateUserRegisterTypes(CompanyUserDO companyUser) {
        if (Boolean.FALSE.equals(companyUser.getIsCustomer())
                && Boolean.FALSE.equals(companyUser.getIsSupplier())) {
            companyUser.setIsCustomer(true);
            companyUser.setIsSupplier(false);
        }
    }

    @Override
    public List<CompanyUserIndexRspDTO> listByCompanyIds(List<Long> companyIds) {

        if (CollUtil.isEmpty(companyIds)) {
            return new ArrayList<>();
        }

        List<CompanyUserDO> companyUserDOS = companyUserMapper.listByCompanyIds(companyIds);
        if (CollUtil.isEmpty(companyUserDOS)) {
            return new ArrayList<>();
        }
        List<CompanyUserIndexRspDTO> result = new ArrayList<>();
        companyUserDOS.forEach(companyUserDO -> {

            CompanyUserIndexRspDTO companyUserIndexRspDTO = new CompanyUserIndexRspDTO();
            BeanUtils.copyProperties(companyUserDO, companyUserIndexRspDTO);
            companyUserIndexRspDTO.setIsLockedBuy(FieldUtils.boolean2Integer(companyUserDO.getIsLockedBuy()));
            companyUserIndexRspDTO.setIsLockedSale(FieldUtils.boolean2Integer(companyUserDO.getIsLockedSale()));
            companyUserIndexRspDTO.setUserId(companyUserDO.getId());
            result.add(companyUserIndexRspDTO);
        });
        return result;
    }

    @Override
    public List<CompanyUserKeyFieldRspDTO> listValidEmailByIds(Integer notifyBitmap, List<Long> ids) {
        if (CollectionUtils.isEmpty(ids) || notifyBitmap == null) {
            return Collections.emptyList();
        }
        // 按业务开关过滤
        ids = companyUserInformationMapper.listByIds(ids)
                .stream().filter(e ->
                        e.getNotifyBitmap().length() <= notifyBitmap || e.getNotifyBitmap().charAt(notifyBitmap) == '0'
                ).map(CompanyUserInformationDO::getId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return companyUserMapper.listByIds(ids)
                .stream()
                .filter(e -> StringUtils.hasText(FieldUtils.unwrapString(e.getEmail())))
                .filter(CompanyUserDO::getIsVerifiedEmail)
                .map(e -> CompanyUserKeyFieldRspDTO.builder()
                        .id(e.getId())
                        .name(e.getName())
                        .email(FieldUtils.unwrapString(e.getEmail()))
                        .build()).collect(Collectors.toList());
    }

    @Override
    public void updateIsSupplierCustomer(CompanyUserUpdateIsSupplierCustomerReqDTO reqDTO) {
        Boolean isCustomer = reqDTO.getIsCustomer();
        Boolean isSupplier = reqDTO.getIsSupplier();
        CompanyUserDO user = companyUserMapper.getById(reqDTO.getId());
        CompanyDO company = companyMapper.selectById(user.getCompanyId());
        if (isCustomer != null && isCustomer) {
            if (!user.getIsCustomer()) {
                companyUserMapper.updateByIdSelective(
                        CompanyUserDO.builder()
                                .id(user.getId())
                                .isCustomer(true)
                                .build());
            }
            if (!company.getIsCustomer().equals(1)) {
                companyMapper.updateById(
                        CompanyDO.builder()
                                .id(company.getId())
                                .isCustomer(1)
                                .build());
            }
        }
        if (isSupplier != null && isSupplier) {
            if (!user.getIsSupplier()) {
                companyUserMapper.updateByIdSelective(
                        CompanyUserDO.builder()
                                .id(user.getId())
                                .isSupplier(true)
                                .build());
            }
            if (!company.getIsSupplier().equals(1)) {
                companyMapper.updateById(
                        CompanyDO.builder()
                                .id(company.getId())
                                .isSupplier(1)
                                .build());
            }
        }
    }

    @Transactional
    @Override
    public CompanyUserKeyFieldRspDTO authentication(CompanyUserLoginReqDTO reqDTO) {
        Assert.notNull(reqDTO.getUsername(), "用户名不能为空");
        Assert.notNull(reqDTO.getPassword(), "密码不能为空");

        CompanyUserDO user;
        if (Validator.isEmail(reqDTO.getUsername())) {
            List<CompanyUserDO> users = companyUserMapper.listBy(
                    CompanyUserQO.builder().email(reqDTO.getUsername()).build());
            user = !users.isEmpty() ? users.get(0) : null;
        } else if (Validator.isMobile(reqDTO.getUsername())) {
            List<CompanyUserDO> users = companyUserMapper.listBy(
                    CompanyUserQO.builder().mobile(reqDTO.getUsername()).build());
            user = !users.isEmpty() ? users.get(0) : null;
        } else {
            return null;
        }

        if (null == user) {
            return null;
        } else {
            if (user.getIsLogout()) {
                throw new UserLoginFailedException("用户已注销");
            }
        }

        if (!passwordEncoder.validate(user.getPassword(), reqDTO.getPassword())) {
            companyUserMapper.updateByIdSelective(
                    CompanyUserDO.builder().id(user.getId()).failedLogins(user.getFailedLogins() + 1)
                            .lastLoginTime(new Date()).lastLoginIp(reqDTO.getIp())
                            .updateTime(new Date()).build());
            return null;
        }

        companyUserMapper.updateByIdSelective(
                CompanyUserDO.builder().id(user.getId()).loginTimes(user.getLoginTimes() + 1)
                        .lastLoginTime(new Date()).lastLoginIp(reqDTO.getIp())
                        .updateTime(new Date()).build());
        CompanyUserInformationDO userInfo = companyUserInformationMapper.getById(user.getId());

        CompanyUserKeyFieldRspDTO rspDTO = new CompanyUserKeyFieldRspDTO();
        BeanUtils.copyProperties(user, rspDTO);
        rspDTO.setAvatar(userInfo.getAvatar());
        return rspDTO;
    }

    @Transactional
    @Override
    public Long register(CompanyUserRegisterReqDTO reqDTO) {
        Assert.isTrue(reqDTO.getType() != null && reqDTO.getUsername() != null
                && reqDTO.getPassword() != null, "参数错误");
        companyUserValidator.validatePassword(reqDTO.getPassword(), false);
        List<CompanyUserDO> users = companyUserMapper.listBy(
                CompanyUserQO.builder().mobile(reqDTO.getUsername()).build());
        Assert.isTrue(users.isEmpty(), "账号已存在，不能重复注册");
        // 新增公司
        CompanyDO company = new CompanyDO();
        company.setName(reqDTO.getUsername());
        company.setNameAbbr(FieldUtils.wrapString(null));
        company.setCompanySource(CompanySourceEnum.SELF_REGISTER.getValue());
        company.setCreateTime(new Date());
        try {
            companyMapper.insert(company);
        } catch (DuplicateKeyException e) {
            throw new IllegalArgumentException("账号已存在，不能重复注册");
        }
        CompanyInformationDO companyInfo = new CompanyInformationDO();
        companyInfo.setId(company.getId());
        companyInformationMapper.saveSelective(companyInfo);
        // 新增用户
        CompanyUserDO user = CompanyUserDO.builder()
                .email(FieldUtils.wrapString(null))
                .password(passwordEncoder.encode(reqDTO.getPassword()))
                .name(reqDTO.getUsername())
                .mobile(reqDTO.getUsername())
                .companyId(company.getId())
                .isVerifiedEmail(null)
                .isVerifiedMobile(true)
                .platformType(reqDTO.getPlatformType() != null ? reqDTO.getPlatformType() : PlatformTypeEnum.PC.getValue())
//                .defaultUser(1)
                .pageSource(reqDTO.getPageSource())
                .isPrecursor(UserPageSourceEnum.PC_PRECURSOR.getValue().equals(reqDTO.getPageSource()) ? 1 : 0)
                .createTime(new Date()).createType(OperatorTypeEnum.USER.getValue()).build();
        companyUserMapper.insertSelective(user);
        companyUserInformationMapper.insertSelective(CompanyUserInformationDO.builder().id(user.getId()).build());
        String desc = user.getPlatformType().equals(PlatformTypeEnum.PC.getValue()) ? "PC" : "微信";
        CompanyLogDO logDO = CompanyLogDO.builder()
                .companyId(company.getId())
                .createType(OperatorTypeEnum.USER.getValue())
                .createId(user.getId())
                .operationType(CompanyLogOperationTypeEnum.UPDATE_USER_INFORMATION.getValue())
                .operationDesc1(desc + "新增用户\"" + reqDTO.getUsername() + "\""
                )
                .createTime(new Date())
                .ip(reqDTO.getIp())
                .build();
        companyLogMapper.insertSelective(logDO);
        return user.getId();
    }

    @Transactional
    @Override
    public CompanyUserNewUserApplyDTO newUserApply(CompanyUserNewUserApplyDTO reqDTO) {
        log.info("新用户申请参数，{}", reqDTO.toString());
        ProcessInstanceCompletedMessageReqDTO approveMessage = reqDTO.getApproveMessage();
        // 这里的代码我真改吐了，对象又被覆盖
        // 别说 我也要改吐了，字段改成表了，谁改谁知道
        // 又来了，部门职位字段一开始就搞反了，反了啊，反了，崩溃
        Long traderId = reqDTO.getTraderId();
        String traderDepartmentPath = reqDTO.getTraderDepartmentPath();
        if (approveMessage != null) {// 审批通过/驳回
            reqDTO = (CompanyUserNewUserApplyDTO) companyAndUserApplicationService.finishWorkflow(approveMessage);
        }
        Long id = reqDTO.getId();
        CompanyUserDO user = companyUserMapper.getById(id);
        CompanyDO company = companyMapper.selectById(user.getCompanyId());
        // 公司业务性质
        List<CompanyIndustryTypeDO> companyIndustryTypeList = companyIndustryTypeMapper
                .selectList(Wrappers.<CompanyIndustryTypeDO>lambdaQuery()
                        .eq(CompanyIndustryTypeDO::getCompanyId, company.getId()));
        CompanyInformationDO companyInfo = companyInformationMapper.getById(user.getCompanyId());
        List<CompanyBusinessLicenseDO> licenses = companyBusinessLicenseMapper.selectBy(
                CompanyBusinessLicenseQO.builder().companyId(user.getCompanyId())
                        .effective(true).orderBy("id desc").build());
        List<CompanyAndUserApplicationDO> applications = companyAndUserApplicationMapper.selectBy(
                CompanyAndUserApplicationQO.builder().userId(id)
                        .applicationType(CompanyAndUserApplicationTypeEnum.NEW_USER_APPLICATION.getValue())
                        .orderBy("id desc").build());
        Assert.isTrue(applications.isEmpty()
                        || applications.get(0).getApprovalStatus() != ApprovalStatusEnum.REVIEW.getValue(),
                "有在途的申请，不能操作");
        Date now = new Date();
        CompanyUserNewUserApplyDTO rspDTO = new CompanyUserNewUserApplyDTO();
        // 发起审批流
        if (approveMessage == null) {
            BeanUtils.copyProperties(user, reqDTO);
            reqDTO.setMobile(FieldUtils.unwrapString(user.getMobile()));
            reqDTO.setEmail(FieldUtils.unwrapString(user.getEmail()));
            reqDTO.setCompanyName(FieldUtils.unwrapString(company.getName()));
            if (CollUtil.isNotEmpty(companyIndustryTypeList)) {
                reqDTO.setCompanyTypeList(companyIndustryTypeList.stream().map(c -> {
                    CompanyKeyFieldDTO.Type type = new CompanyKeyFieldDTO.Type();
                    type.setFirstType(c.getFirstType());
                    if (StringUtils.hasText(c.getSecondType())) {
                        type.setSecondTypeList(FieldUtils.unwrapArray(c.getSecondType(), "-", Integer.class));
                    } else {
                        type.setSecondTypeList(Collections.emptyList());
                    }
                    return type;
                }).collect(Collectors.toList()));
            }
            reqDTO.setProvince(company.getProvince());
            reqDTO.setCity(company.getCity());
            reqDTO.setDistrict(company.getDistrict());
            reqDTO.setAddress(companyInfo.getAddress());
            reqDTO.setTel(companyInfo.getTel());
            reqDTO.setSocialCreditCode(!licenses.isEmpty() ? licenses.get(0).getSocialCreditCode() : null);
            reqDTO.setBusinessEndDate(!licenses.isEmpty() ? licenses.get(0).getBusinessEndDate() : null);
            reqDTO.setCertificateUrl(!licenses.isEmpty() ? licenses.get(0).getCertificateUrl() : null);
            CompanyAndUserApplicationDO application = CompanyAndUserApplicationDO.builder()
                    .applicationType(CompanyAndUserApplicationTypeEnum.NEW_USER_APPLICATION.getValue())
                    .applicantId(reqDTO.getOperator().getOperatorId())
                    .companyId(user.getCompanyId())
                    .traderId(company.getTraderId())
                    .traderDepartmentPath(company.getTraderDepartmentPath())
                    .userId(id)
                    .createId(reqDTO.getOperator().getOperatorId())
                    .createTime(now)
                    .build();
            companyAndUserApplicationMapper.insertSelective(application);
            companyAndUserApplicationInfoMapper.insertSelective(
                    CompanyAndUserApplicationInformationDO.builder()
                            .id(application.getId())
                            .applicantParam(JSONUtil.toJsonStr(reqDTO)).build());
            rspDTO.setApplicationId(application.getId());
            return rspDTO;
        }
        // 审批通过/驳回
        if (approveMessage.getApprovalStatus() != ApprovalStatusEnum.PASSED.getValue()) {
            companyUserMapper.updateByIdSelective(CompanyUserDO.builder()
                    .id(id)
                    .verified(-1)
                    .updateTime(now)
                    .build());
            return rspDTO;
        }
        // 审批通过
        companyUserMapper.updateByIdSelective(CompanyUserDO.builder().id(id).name(reqDTO.getName())
                .verified(1)
                .mobile(FieldUtils.wrapString(reqDTO.getMobile()))
                .email(FieldUtils.wrapString(reqDTO.getEmail()))
                .qq(reqDTO.getQq())
                .isSupplier(Integer.valueOf(1).equals(reqDTO.getIsSupplier()))
                .isCustomer(Integer.valueOf(1).equals(reqDTO.getIsCustomer()))
                .updateTime(now).build());
        companyUserInformationMapper.updateByIdSelective(CompanyUserInformationDO.builder()
                .id(id)
                .invoiceEmail(reqDTO.getInvoiceEmail())
                .department(Optional.ofNullable(reqDTO.getDepartment()).orElse(""))
                .build());
        CompanyDO companyExists = companyMapper.getByName(reqDTO.getCompanyName());
        if (companyExists == null) {
            // 更新公司信息
            companyMapper.updateById(CompanyDO.builder().id(user.getCompanyId())
                    .verified(1)
                    .isSupplier(reqDTO.getIsSupplier())
                    .isCustomer(reqDTO.getIsCustomer())
                    .name(reqDTO.getCompanyName())
                    .mcode(PinyinUtils.toPinyinFirstLetters(reqDTO.getCompanyName()))
                    .province(reqDTO.getProvince())
                    .city(reqDTO.getCity())
                    .district(reqDTO.getDistrict())
                    .traderId(traderId)
                    .traderDepartmentPath(traderDepartmentPath)
                    .updateTime(now).build());
            // 更新公司行业类型信息
            companyIndustryTypeService.saveOrUpdate(CompanyIndustryTypeCreateOrUpdateDTO.builder()
                    .companyId(user.getCompanyId())
                    .typeList(CollUtil.isEmpty(reqDTO.getCompanyTypeList()) ? Collections.emptyList() : reqDTO.getCompanyTypeList()
                            .stream()
                            .map(c -> {
                                CompanyKeyFieldDTO.Type type = new CompanyKeyFieldDTO.Type();
                                type.setFirstType(c.getFirstType());
                                type.setSecondTypeList(c.getSecondTypeList());
                                return type;
                            }).collect(Collectors.toList()))
                    .build(), OperatorReqDTO.SYSTEM);

            if (reqDTO.getAddress() != null || reqDTO.getTel() != null) {
                companyInformationMapper.updateByIdSelective(CompanyInformationDO.builder().id(user.getCompanyId())
                        .address(reqDTO.getAddress())
                        .tel(reqDTO.getTel())
                        .build());
            }
        } else {// 数据迁移
            Long oldCompanyId = user.getCompanyId();
            try {
                companyUserMapper.updateByIdSelective(CompanyUserDO.builder().id(id)
                        .companyId(companyExists.getId())
                        .updateTime(now).build());
            } catch (Exception e) {
                companyUserMapper.updateByIdSelective(CompanyUserDO.builder().id(id)
                        .companyId(companyExists.getId())
                        .defaultUser(FieldUtils.wrapDefault(null)).updateTime(now).build());
            }
            companyLogMapper.insertSelective(CompanyLogDO
                    .builder()
                    .companyId(companyExists.getId())
                    .createType(OperatorTypeEnum.SYSTEM.getValue())
                    .createId(0L)
                    .createTime(new Date())
                    .operationType(CompanyLogOperationTypeEnum.UPDATE_USER_INFORMATION.getValue())
                    .operationDesc1(String.format("%s 新增用户 %s", Optional.ofNullable(PlatformTypeEnum.fromValue(user.getPlatformType()))
                            .map(PlatformTypeEnum::getName)
                            .orElse("未知"), reqDTO.getName()))
//                    .ip(reqDTO.getOperator().getIp())
                    .build());
            CompanyDO updateCompanyDO = CompanyDO.builder()
                    .id(companyExists.getId())
                    .verified(1)
                    .isSupplier(companyExists.getIsSupplier() == 0 ? reqDTO.getIsSupplier() : null)
                    .isCustomer(companyExists.getIsCustomer() == 0 ? reqDTO.getIsCustomer() : null)
                    .traderId(traderId)
                    .traderDepartmentPath(traderDepartmentPath)
                    .province(Objects.equals(0,reqDTO.getProvince()) ? null : reqDTO.getProvince())
                    .city(Objects.equals(0,reqDTO.getCity()) ? null : reqDTO.getCity())
                    .district(Objects.equals(0,reqDTO.getDistrict()) ? null : reqDTO.getDistrict())
                    .updateTime(now)
                    .build();


            if(CollUtil.isNotEmpty(reqDTO.getCompanyTypeList())){
                // 更新公司行业类型信息
                companyIndustryTypeService.saveOrUpdate(CompanyIndustryTypeCreateOrUpdateDTO.builder()
                        .companyId(user.getCompanyId())
                        .typeList(CollUtil.isEmpty(reqDTO.getCompanyTypeList()) ? Collections.emptyList() : reqDTO.getCompanyTypeList()
                                .stream()
                                .map(c -> {
                                    CompanyKeyFieldDTO.Type type = new CompanyKeyFieldDTO.Type();
                                    type.setFirstType(c.getFirstType());
                                    type.setSecondTypeList(c.getSecondTypeList());
                                    return type;
                                }).collect(Collectors.toList()))
                        .build(), OperatorReqDTO.SYSTEM);
            }



            if (reqDTO.getAddress() != null || reqDTO.getTel() != null) {
                companyInformationMapper.updateByIdSelective(CompanyInformationDO.builder().id(user.getCompanyId())
                        .address(reqDTO.getAddress())
                        .tel(reqDTO.getTel())
                        .build());
            }

            // 旧公司如果没有用户，则删除
            if (companyUserMapper.listBy(CompanyUserQO.builder().companyId(oldCompanyId).isLogout(false).build())
                    .isEmpty()) {
                CompanyDO oldCompany = companyMapper.selectById(oldCompanyId);
                if (oldCompany != null) {
                    companyMapper.updateById(CompanyDO.builder()
                            .id(oldCompany.getId())
                            .deleted(FieldUtils.wrapDelete(1))
                            .updateTime(now)
                            .build());
                    if (Optional.ofNullable(DateUtils.filterDate(oldCompany.getFirstOrderTime()))
                            .map(oc -> Optional.ofNullable(DateUtils.filterDate(companyExists.getFirstOrderTime()))
                                    .map(nc -> oc.before(nc))
                                    .orElse(true))
                            .orElse(false)) {
                        updateCompanyDO.setFirstOrderTime(oldCompany.getFirstOrderTime());
                    }
                    if (Optional.ofNullable(DateUtils.filterDate(oldCompany.getPrevOrderTime()))
                            .map(oc -> Optional.ofNullable(DateUtils.filterDate(companyExists.getPrevOrderTime()))
                                    .map(nc -> oc.after(nc))
                                    .orElse(true))
                            .orElse(false)) {
                        updateCompanyDO.setPrevOrderTime(oldCompany.getPrevOrderTime());
                    }
                    if (Optional.ofNullable(DateUtils.filterDate(oldCompany.getLastOrderTime()))
                            .map(oc -> Optional.ofNullable(DateUtils.filterDate(companyExists.getLastOrderTime()))
                                    .map(nc -> oc.after(nc))
                                    .orElse(true))
                            .orElse(false)) {
                        updateCompanyDO.setLastOrderTime(oldCompany.getLastOrderTime());
                    }
                    if (Optional.ofNullable(DateUtils.filterDate(oldCompany.getFirstInquiryTime()))
                            .map(oc -> Optional.ofNullable(DateUtils.filterDate(companyExists.getFirstInquiryTime()))
                                    .map(nc -> oc.before(nc))
                                    .orElse(true))
                            .orElse(false)) {
                        updateCompanyDO.setFirstInquiryTime(oldCompany.getFirstInquiryTime());
                    }
                    if (Optional.ofNullable(DateUtils.filterDate(oldCompany.getPrevInquiryTime()))
                            .map(oc -> Optional.ofNullable(DateUtils.filterDate(companyExists.getPrevInquiryTime()))
                                    .map(nc -> oc.after(nc))
                                    .orElse(true))
                            .orElse(false)) {
                        updateCompanyDO.setPrevInquiryTime(oldCompany.getPrevInquiryTime());
                    }
                    if (Optional.ofNullable(DateUtils.filterDate(oldCompany.getLastInquiryTime()))
                            .map(oc -> Optional.ofNullable(DateUtils.filterDate(companyExists.getLastInquiryTime()))
                                    .map(nc -> oc.after(nc))
                                    .orElse(true))
                            .orElse(false)) {
                        updateCompanyDO.setLastInquiryTime(oldCompany.getLastInquiryTime());
                    }
                    if (Optional.ofNullable(DateUtils.filterDate(oldCompany.getSupplierFirstOrderTime()))
                            .map(oc -> Optional.ofNullable(DateUtils.filterDate(companyExists.getSupplierFirstOrderTime()))
                                    .map(nc -> oc.before(nc))
                                    .orElse(true))
                            .orElse(false)) {
                        updateCompanyDO.setSupplierFirstOrderTime(oldCompany.getSupplierFirstOrderTime());
                    }
                    if (Optional.ofNullable(DateUtils.filterDate(oldCompany.getSupplierFirstShipTime()))
                            .map(oc -> Optional.ofNullable(DateUtils.filterDate(companyExists.getSupplierFirstShipTime()))
                                    .map(nc -> oc.before(nc))
                                    .orElse(true))
                            .orElse(false)) {
                        updateCompanyDO.setSupplierFirstShipTime(oldCompany.getSupplierFirstShipTime());
                    }
                }
            }
            user.setCompanyId(companyExists.getId());
            companyMapper.updateById(updateCompanyDO);
            companyInformationMapper.updateByIdSelective(CompanyInformationDO.builder()
                    .id(user.getCompanyId())
                    .precursorEnterpriseId(companyInfo.getPrecursorEnterpriseId())
                    .build());
            rspDTO.setIsCompanyChanged(true);
            rspDTO.setId(id);
        }
        // 如果用户 page_source=14004(PC端易制毒) & 对应的公司 company_source=0 则 设置company_source=page_source
        CompanyUserDO userDO = companyUserMapper.getById(id);
        int count = companyUserMapper.countByCompanyId(user.getCompanyId());
        if (userDO != null
                && Objects.equals(14004, userDO.getPageSource())
                && count <= 1) {
            CompanyDO update = new CompanyDO();
            update.setId(user.getCompanyId());
            update.setCompanySource(11);
            companyMapper.updateById(update);
        }
        // 营业执照
        if (!StringUtils.hasText(reqDTO.getSocialCreditCode())) {
            return rspDTO;
        }
        licenses = companyBusinessLicenseMapper.selectBy(
                CompanyBusinessLicenseQO.builder().companyId(user.getCompanyId())
                        .socialCreditCode(reqDTO.getSocialCreditCode()).orderBy("id desc").build());
        if (licenses.isEmpty()) {
            companyBusinessLicenseMapper.insert(CompanyBusinessLicenseDO.builder()
                    .effective(1)
                    .companyId(user.getCompanyId())
                    .socialCreditCode(reqDTO.getSocialCreditCode())
                    .businessEndDate(reqDTO.getBusinessEndDate())
                    .certificateUrl(reqDTO.getCertificateUrl())
                    .createTime(now).build());
        }
        // 公司日志
        CompanyLogDO logDO = CompanyLogDO.builder()
                .companyId(user.getCompanyId())
                .createType(OperatorTypeEnum.EMPLOYEE.getValue())
                .createId(approveMessage.getVerifyId())
                .operationType(CompanyLogOperationTypeEnum.NEW_USER_APPROVAL.getValue())
                .operationDesc1("审核通过用户“" +
                        Stream.of(reqDTO.getName(), reqDTO.getEmail(), reqDTO.getMobile())
                                .filter(e -> StringUtils.hasText(e)).collect(Collectors.joining(" ")) + "”")
                .ip(null).createTime(now).build();
        companyLogMapper.insertSelective(logDO);
        return rspDTO;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public CompanyUserSupplierApplyDTO supplierApply(CompanyUserSupplierApplyDTO reqDTO) {
        ProcessInstanceCompletedMessageReqDTO approveMessage = reqDTO.getApproveMessage();
        if (approveMessage != null) {// 审批通过/驳回
            reqDTO = (CompanyUserSupplierApplyDTO) companyAndUserApplicationService.finishWorkflow(approveMessage);
        }
        Long id = reqDTO.getId();
        CompanyUserDO user = companyUserMapper.getById(id);
        List<CompanyAndUserApplicationDO> applications = companyAndUserApplicationMapper.selectBy(
                CompanyAndUserApplicationQO.builder().userId(id)
                        .applicationType(CompanyAndUserApplicationTypeEnum.SUPPLIER_POWER_APPLICATION.getValue())
                        .orderBy("id desc").build());
        Assert.isTrue(applications.isEmpty()
                        || applications.get(0).getApprovalStatus() != ApprovalStatusEnum.REVIEW.getValue(),
                "有在途的申请，不能操作");
        Date now = new Date();
        CompanyUserSupplierApplyDTO rspDTO = new CompanyUserSupplierApplyDTO();
        if (approveMessage == null) {// 发起审批流
            CompanyAndUserApplicationDO application = CompanyAndUserApplicationDO.builder()
                    .applicationType(CompanyAndUserApplicationTypeEnum.SUPPLIER_POWER_APPLICATION.getValue())
                    .applicantId(reqDTO.getOperator().getOperatorId())
                    .companyId(user.getCompanyId())
                    .userId(id)
                    .createId(reqDTO.getOperator().getOperatorId())
                    .createTime(now)
                    .build();
            companyAndUserApplicationMapper.insertSelective(application);
            companyAndUserApplicationInfoMapper.insertSelective(
                    CompanyAndUserApplicationInformationDO.builder()
                            .id(application.getId())
                            .applicantParam(JSONUtil.toJsonStr(reqDTO)).build());
            rspDTO.setApplicationId(application.getId());
            return rspDTO;
        }
        // 审批通过/驳回
        if (approveMessage.getApprovalStatus() != ApprovalStatusEnum.PASSED.getValue()) {
            return rspDTO;
        }
        // 审批通过
        // 如果公司名称是手机号，则把营业执照公司名称更新到公司上，公司名称已存在则做用户迁移
        CompanyDO companyOld = companyMapper.selectById(user.getCompanyId());
        if (Validator.isMobile(companyOld.getName()) && !reqDTO.getCompanyName().equals(companyOld.getName())) {
            CompanyDO companyExists = companyMapper.getByName(reqDTO.getCompanyName());
            if (companyExists != null) {
                try {
                    companyUserMapper.updateByIdSelective(CompanyUserDO.builder().id(id)
                            .companyId(companyExists.getId())
                            .updateTime(now).build());
                } catch (Exception e) {
                    companyUserMapper.updateByIdSelective(CompanyUserDO.builder().id(id)
                            .companyId(companyExists.getId())
                            .defaultUser(FieldUtils.wrapDefault(null))
                            .updateTime(now).build());
                }
                user.setCompanyId(companyExists.getId());
            } else {
                companyMapper.updateById(CompanyDO.builder().id(user.getCompanyId())
                        .name(reqDTO.getCompanyName())
                        .updateTime(now).build());
            }
        }
        companyUserMapper.updateByIdSelective(CompanyUserDO.builder().id(id)
                .isSupplier(true)
                .updateTime(now).build());
        companyMapper.updateById(CompanyDO.builder().id(user.getCompanyId())
                .isSupplier(1)
                .updateTime(now).build());
        // 营业执照
        if (!StringUtils.hasText(reqDTO.getCertificateUrl())) {
            return rspDTO;
        }
        List<CompanyBusinessLicenseDO> licenses = companyBusinessLicenseMapper.selectBy(
                CompanyBusinessLicenseQO.builder().companyId(user.getCompanyId())
                        .socialCreditCode(reqDTO.getSocialCreditCode()).effective(true).build());
        if (licenses.isEmpty()) {
            companyBusinessLicenseMapper.insert(CompanyBusinessLicenseDO.builder()
                    .effective(1)
                    .companyName(reqDTO.getCompanyName())
                    .companyId(user.getCompanyId())
                    .socialCreditCode(reqDTO.getSocialCreditCode())
                    .legalPerson(reqDTO.getLegalPerson())
                    .establishmentDate(reqDTO.getEstablishmentDate())
                    .businessStartDate(reqDTO.getEstablishmentDate())
                    .businessEndDate(reqDTO.getBusinessEndDate())
                    .certificateUrl(reqDTO.getCertificateUrl())
                    .createTime(now).build());
        } else {
            companyBusinessLicenseMapper.update(CompanyBusinessLicenseDO.builder()
                    .id(licenses.get(0).getId())
                    .companyName(reqDTO.getCompanyName())
                    .socialCreditCode(reqDTO.getSocialCreditCode())
                    .legalPerson(reqDTO.getLegalPerson())
                    .establishmentDate(reqDTO.getEstablishmentDate())
                    .businessStartDate(reqDTO.getEstablishmentDate())
                    .businessEndDate(reqDTO.getBusinessEndDate())
                    .certificateUrl(reqDTO.getCertificateUrl())
                    .updateTime(now).build());
        }
        return rspDTO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void resetPassword(CompanyUserResetPasswordReqDTO reqDTO) {
        companyUserValidator.validatePassword(reqDTO.getPassword(), false);
        companyUserMapper.updateByIdSelective(CompanyUserDO.builder()
                .id(reqDTO.getId())
                .password(passwordEncoder.encode(reqDTO.getPassword()))
                .resetPasswordTime(new Date()).build());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void bind(CompanyUserBindReqDTO reqDTO) {
        CompanyUserDO userOld;
        if (reqDTO.getType() == 1) {
            List<CompanyUserDO> users = companyUserMapper.listBy(
                    CompanyUserQO.builder().mobile(reqDTO.getMobile()).build());
            userOld = !users.isEmpty() ? users.get(0) : null;
            if (userOld != null) {
                if (userOld.getId() == reqDTO.getId().longValue()) {
                    throw new IllegalArgumentException("已绑定该手机号，不能重复操作");
                } else {
                    throw new IllegalArgumentException("该手机号已被使用，不能操作");
                }
            }
        } else {
            List<CompanyUserDO> users = companyUserMapper.listBy(
                    CompanyUserQO.builder().email(reqDTO.getEmail()).build());
            userOld = !users.isEmpty() ? users.get(0) : null;
            if (userOld != null) {
                if (userOld.getId() == reqDTO.getId().longValue()) {
                    throw new IllegalArgumentException("已绑定该邮箱，不能重复操作");
                } else {
                    throw new IllegalArgumentException("该邮箱已被使用，不能操作");
                }
            }
        }
        companyUserMapper.updateByIdSelective(CompanyUserDO.builder()
                .id(reqDTO.getId())
                .mobile(reqDTO.getType() == 1 ? reqDTO.getMobile() : null)
                .email(reqDTO.getType() == 2 ? reqDTO.getEmail() : null)
                .isVerifiedMobile(reqDTO.getType() == 1 ? true : null)
                .isVerifiedEmail(reqDTO.getType() == 2 ? true : null)
                .updateTime(new Date()).build());
    }

    @Transactional
    @Override
    public void fillData(CompanyUserFillDataReqDTO reqDTO) {
        CompanyUserDO userOld = companyUserMapper.getById(reqDTO.getId());
        CompanyUserDO user = new CompanyUserDO();
        BeanUtils.copyProperties(reqDTO, user);
        user.setUpdateTime(new Date());
        companyUserMapper.updateByIdSelective(user);
        CompanyUserInformationDO userInfo = new CompanyUserInformationDO();
        BeanUtils.copyProperties(reqDTO, userInfo);
        companyUserInformationMapper.updateByIdSelective(userInfo);
        CompanyDO company = new CompanyDO();
        company.setId(userOld.getCompanyId());
        company.setName(StringUtils.hasText(reqDTO.getCompanyName()) ? reqDTO.getCompanyName() : null);
        company.setUpdateTime(new Date());
        try {
            companyMapper.updateById(company);
        } catch (Exception e) {
            if (StringUtils.hasText(reqDTO.getCompanyName())) {
                company.setName(reqDTO.getCompanyName() + userOld.getMobile());
                try {// 这里捕捉异常是为了针对反复注册导致的数据问题
                    companyMapper.updateById(company);
                } catch (Exception e2) {
                }
            }
        }
        // 更新待审核信息里的公司名称
        if (StringUtils.hasText(reqDTO.getCompanyName())) {
            companyAndUserApplicationMapper.selectBy(CompanyAndUserApplicationQO.builder()
                            .userId(reqDTO.getId())
                            .applicationType(CompanyAndUserApplicationTypeEnum.NEW_USER_APPLICATION.getValue())
                            .approvalStatus(ApprovalStatusEnum.REVIEW.getValue())
                            .build())
                    .forEach(e -> {
                        CompanyUserNewUserApplyDTO dto = JSONUtil.toBean(
                                companyAndUserApplicationInfoMapper.selectById(e.getId()).getApplicantParam(),
                                CompanyUserNewUserApplyDTO.class);
                        dto.setCompanyName(reqDTO.getCompanyName());
                        companyAndUserApplicationInfoMapper.updateByIdSelective(
                                CompanyAndUserApplicationInformationDO.builder().id(e.getId())
                                        .applicantParam(JSONUtil.toJsonStr(dto)).build());
                    });
        }
    }

    @Transactional
    @Override
    public CompanyUserAccountUpdateApplyDTO accountUpdateApply(CompanyUserAccountUpdateApplyDTO reqDTO) {
        ProcessInstanceCompletedMessageReqDTO approveMessage = reqDTO.getApproveMessage();
        if (approveMessage != null) {// 审批通过/驳回
            reqDTO = (CompanyUserAccountUpdateApplyDTO) companyAndUserApplicationService.finishWorkflow(approveMessage);
        }
        Long id = reqDTO.getId();
        CompanyUserDO user = companyUserMapper.getById(id);
        List<CompanyAndUserApplicationDO> applications = companyAndUserApplicationMapper.selectBy(
                CompanyAndUserApplicationQO.builder().userId(id)
                        .applicationType(CompanyAndUserApplicationTypeEnum.ACCOUNT_UPDATE_APPLICATION.getValue())
                        .orderBy("id desc").build());
        Assert.isTrue(applications.isEmpty()
                        || applications.get(0).getApprovalStatus() != ApprovalStatusEnum.REVIEW.getValue(),
                "有在途的申请，不能操作");
        Date now = new Date();
        CompanyUserAccountUpdateApplyDTO rspDTO = new CompanyUserAccountUpdateApplyDTO();
        if (approveMessage == null) {// 发起审批流
            reqDTO.setName(user.getName());
            reqDTO.setMobile(FieldUtils.unwrapString(user.getMobile()));
            reqDTO.setEmail(FieldUtils.unwrapString(user.getEmail()));
            CompanyAndUserApplicationDO application = CompanyAndUserApplicationDO.builder()
                    .applicationType(CompanyAndUserApplicationTypeEnum.ACCOUNT_UPDATE_APPLICATION.getValue())
                    .applicantId(reqDTO.getOperator().getOperatorId())
                    .companyId(user.getCompanyId())
                    .userId(id)
                    .createId(reqDTO.getOperator().getOperatorId())
                    .createTime(now)
                    .build();
            companyAndUserApplicationMapper.insertSelective(application);
            companyAndUserApplicationInfoMapper.insertSelective(
                    CompanyAndUserApplicationInformationDO.builder()
                            .id(application.getId())
                            .applicantParam(JSONUtil.toJsonStr(reqDTO)).build());
            rspDTO.setApplicationId(application.getId());
            return rspDTO;
        }
        // 审批通过/驳回
        if (approveMessage.getApprovalStatus() != ApprovalStatusEnum.PASSED.getValue()) {
            return rspDTO;
        }
        // 审批通过
        companyUserMapper.updateByIdSelective(CompanyUserDO.builder().id(id).name(reqDTO.getName())
                .mobile(FieldUtils.wrapString(reqDTO.getMobile()))
                .email(FieldUtils.wrapString(reqDTO.getEmail()))
                .updateTime(now).build());
        return rspDTO;
    }

    @Override
    public Integer updateEmailById(Long id, String email) {
        CompanyUserDO companyUserDO = new CompanyUserDO();
        companyUserDO.setId(id);
        companyUserDO.setEmail(email);
        companyUserDO.setIsVerifiedEmail(true);
        companyUserDO.setUpdateId(id);
        companyUserDO.setUpdateTime(new Date());
        companyUserDO.setUpdateType(OperatorTypeEnum.USER.getValue());
        try {
            return companyUserMapper.updateByIdSelective(companyUserDO);
        } catch (Exception exception) {
            return 2;
        }
    }

    @Override
    public void updateInvoiceEmailById(Long id, String email) {
        companyUserInformationMapper.updateByIdSelective(CompanyUserInformationDO.builder().id(id).invoiceEmail(email).build());
    }

    @Override
    public Long findIdByEmail(String email) {
        List<CompanyUserDO> companyUserDOS = companyUserMapper.listBy(CompanyUserQO.builder().email(email).build());
        if (companyUserDOS.isEmpty()) {
            return null;
        }
        return companyUserDOS.get(0).getId();
    }

    @Override
    public CompanyUserDTO infoById(Long id, CompanyUserOptionDTO option) {
        CompanyUserDTO result = new CompanyUserDTO();
        CompanyUserDO companyUser = companyUserMapper.getById(id);
        if (companyUser == null) {
            return new CompanyUserDTO();
        }
        result.setBase(BeanUtil.copyProperties(companyUser, CompanyUserBaseDTO.class));
        result.getBase().setMobile(DatabaseDefaultValueUtils.erasureMillisecondDefaultValueIfExist(result.getBase().getMobile()));
        result.getBase().setEmail(DatabaseDefaultValueUtils.erasureMillisecondDefaultValueIfExist(result.getBase().getEmail()));

        if (option.getIncludeAddress() != null && option.getIncludeAddress()) {
            List<CompanyUserAddressDO> address = companyUserAddressMapper.listBy(CompanyUserAddressQO.builder().userId(id).build());
            result.setAddresses(address.stream().map(item -> BeanUtil.copyProperties(item, CompanyUserAddressDTO.class)).collect(Collectors.toList()));
        }
        if (option.getIncludeErrorCorrection() != null && option.getIncludeErrorCorrection()) {
            result.setErrorCorrections(companyUserErrorCorrectionMapper.selectList(
                            CorrectionQO
                                    .builder()
                                    .userId(id)
                                    .build())
                    .stream()
                    .map(item -> BeanUtil.copyProperties(item, CompanyUserErrorCorrectionDTO.class))
                    .collect(Collectors.toList()));
        }
        if (option.getIncludeInformation() != null && option.getIncludeInformation()) {
            result.setInformation(BeanUtil.copyProperties(companyUserInformationMapper.getById(id), CompanyUserInformationDTO.class));
        }
        if (option.getIncludePlatform() != null && option.getIncludePlatform()) {
            result.setPlatforms(companyUserPlatformMapper.listBy(CompanyUserPlatformQO
                            .builder()
                            .userId(id)
                            .build())
                    .stream()
                    .map(item -> BeanUtil.copyProperties(item, CompanyUserPlatformDTO.class))
                    .collect(Collectors.toList()));
        }
        return result;
    }

    @Override
    public List<CompanyUserListInfoRspDTO> listInfoBy(CompanyUserListInfoQueryReqDTO queryReqDTO) {

        // 查询用户基本信息
        CompanyUserQO companyUserQO = new CompanyUserQO();
        BeanUtils.copyProperties(queryReqDTO, companyUserQO);
        List<CompanyUserDO> companyUserList = companyUserMapper.listBy(companyUserQO);

        if (CollUtil.isEmpty(companyUserList)) {
            return Collections.emptyList();
        }

        List<CompanyUserListInfoRspDTO> result = companyUserList.stream().map(c -> {
            CompanyUserListInfoRspDTO rspDTO = new CompanyUserListInfoRspDTO();
            BeanUtils.copyProperties(c, rspDTO);
            rspDTO.setMobile(DatabaseDefaultValueUtils.erasureMillisecondDefaultValueIfExist(c.getMobile()));
            rspDTO.setEmail(DatabaseDefaultValueUtils.erasureMillisecondDefaultValueIfExist(c.getEmail()));
            return rspDTO;
        }).collect(Collectors.toList());

        // 用户其他信息
        List<Long> userIdList = companyUserList.stream().map(CompanyUserDO::getId).distinct().collect(Collectors.toList());
        List<CompanyUserInformationDO> companyUserInformationList = companyUserInformationMapper.listByIds(userIdList);

        // 用户关注微信公众号信息
        List<CompanyUserPlatformDO> companyUserPlatformList = companyUserPlatformMapper.listBy(CompanyUserPlatformQO.builder()
//                        .thirdPlatformFollowStatus(ThirdPlatformFollowStatusEnum.FOLLOWED.getValue())
                .thirdPlatformType(ThirdPlatformTypeEnum.WECHAT.getValue())
                .isBind(CompanyUserPlatformIsBindEnum.YES.getValue())
                .userIds(userIdList)
                .build());

        result.forEach(r -> {

            // 补充其他信息
            if (CollUtil.isNotEmpty(companyUserInformationList)) {
                companyUserInformationList.stream()
                        .filter(i -> i.getId().equals(r.getId()))
                        .findFirst()
                        .ifPresent(i -> BeanUtils.copyProperties(i, r, "id"));
            }

            // 补充关注微信账号信息
            if (CollUtil.isNotEmpty(companyUserPlatformList)) {
                r.setWechatInfoList(companyUserPlatformList.stream()
                        .filter(p -> p.getUserId().equals(r.getId()))
                        .map(p -> {
                            CompanyUserListInfoRspDTO.WechatInfo wechatInfo = new CompanyUserListInfoRspDTO.WechatInfo();
                            BeanUtils.copyProperties(p, wechatInfo);
                            return wechatInfo;
                        }).collect(Collectors.toList()));
            } else {
                r.setWechatInfoList(Collections.emptyList());
            }
        });

        return result;
    }

    /**
     * 通过邮箱获取用户信息
     *
     * @param email 邮箱
     * @return
     */
    @Override
    public CompanyUserKeyFieldRspDTO findByEmail(String email) {
        CompanyUserKeyFieldRspDTO rspDTO = new CompanyUserKeyFieldRspDTO();
        CompanyUserDO user = companyUserMapper.findByEmail(email);
        CompanyUserInformationDO userInfo = companyUserInformationMapper.getById(user.getId());
        BeanUtils.copyProperties(user, rspDTO);
        BeanUtils.copyProperties(userInfo, rspDTO);
        rspDTO.setMobile(FieldUtils.unwrapString(rspDTO.getMobile()));
        rspDTO.setEmail(FieldUtils.unwrapString(rspDTO.getEmail()));
        return rspDTO;
    }

    @Override
    public CompanyUserKeyFieldRspDTO findByPhoneOrEmail(String phoneOrEmail) {
        CompanyUserDO companyUserDO = companyUserMapper.findByPhoneOrEmail(phoneOrEmail);
        CompanyUserKeyFieldRspDTO rspDTO = new CompanyUserKeyFieldRspDTO();
        BeanUtils.copyProperties(companyUserDO, rspDTO);
        rspDTO.setMobile(FieldUtils.unwrapString(rspDTO.getMobile()));
        rspDTO.setEmail(FieldUtils.unwrapString(rspDTO.getEmail()));
        return rspDTO;
    }

    @Override
    public List<Long> selectByIdsWithShareLocked(List<Long> ids) {
        return companyUserMapper.selectByIdsWithShareLocked(ids);
    }

    @Override
    @Transactional
    public void reVerified(Long id, OperatorReqDTO operatorReqDTO) {
        CompanyUserDO user = companyUserMapper.selectById(id);
        if (user.getVerified() != VerifyEnum.NO.getValue()) {
            throw new IllegalArgumentException("当前认证状态不可操作");
        }
        CompanyDO company = companyMapper.selectById(user.getCompanyId());
        companyUserMapper.updateById(CompanyUserDO.builder()
                .id(user.getId())
                .verified(VerifyEnum.YES.getValue())
                .updateId(operatorReqDTO.getOperatorId())
                .updateType(operatorReqDTO.getOperatorType().getValue())
                .updateTime(new Date())
                .build());
        if (company.getVerified() != VerifyEnum.YES.getValue()) {
            companyMapper.updateById(CompanyDO.builder()
                    .id(company.getId())
                    .verified(VerifyEnum.YES.getValue())
                    .updateId(operatorReqDTO.getOperatorId())
                    .updateTime(new Date())
                    .build());
        }
        companyLogMapper.insert(CompanyLogDO.builder()
                .companyId(company.getId())
                .operationType(CompanyLogOperationTypeEnum.NEW_USER_APPROVAL.getValue())
                .operationDesc1(String.format("账号(%s %s %s)设置为认证通过", user.getName(), FieldUtils.unwrapString(user.getMobile()), FieldUtils.unwrapString(user.getEmail())))
                .ip(operatorReqDTO.getIp())
                .createType(operatorReqDTO.getOperatorType().getValue())
                .createId(operatorReqDTO.getOperatorId())
                .createTime(new Date())
                .build());
    }
}
